package cn.cas.mango.service;

import cn.cas.mango.dto.HotChartValue;
import cn.cas.mango.dto.Message;
import cn.cas.mango.dto.News;
import cn.cas.mango.dto.param.BaseParam;
import cn.cas.mango.dto.param.DetailParam;
import cn.cas.mango.dto.param.DetailSimParam;
import cn.cas.mango.dto.param.QueryParam;
import cn.cas.mango.util.EsTypeTransUtil;
import cn.cas.mango.util.Pair;
import cn.cas.mango.util.RenderDateUtil;
import cn.cas.mango.util.RequestUtil.BuildRequest;
import cn.cas.mango.util.ResponseUtil.ResponseUtil;
import cn.cas.mango.util.paramCheck.DetailSimParamCheckUtil;
import cn.cas.mango.util.paramCheck.QueryParamCheckUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.aggregations.CalendarInterval;
import co.elastic.clients.elasticsearch._types.aggregations.DateHistogramBucket;

import co.elastic.clients.elasticsearch._types.aggregations.StringTermsBucket;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;


import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 基于关键词、实体、搜索获取相似新闻
 */
@Service
@Slf4j
public class GetReCmdByService extends BaseService {
  @Autowired
  private ElasticsearchClient elasticsearchClient;
  @Autowired
  private ConfigService config;
  @Autowired
  private DetailService detailService;
  @Value("${elasticsearch.newsDetail.pageSize}")
  private Integer detailPageSize;
  @Autowired
  private BuildRequest buildRequest;
  @Autowired
  private CountService countService;
  @Override
  public Message run(BaseParam baseParam) {

    DetailSimParam detailSimParam = (DetailSimParam) baseParam;
    Map<String, Object> errMessage = DetailSimParamCheckUtil.checkParam(detailSimParam);
    String isSuccess = (String) errMessage.get("isSuccess");
    if (!isSuccess.equals("ok")) {
      return Message.unSuccess(isSuccess);
    }

//    QueryParam queryParam = wrapQueryParam(baseParam, detailPageSize);
//    SearchRequest.Builder builder = buildRequest.buildQueryStrRequest(queryParam);
//    SearchRequest searchRequest = builder.sort((SortOptions) queryParam.get3Sorts().get(2)).build();
//    log.info("Search sim Request Json:{}", searchRequest.toString().split("typed_keys=true")[1]);
//    try {
//      new FileOutputStream("temp2.txt").write(searchRequest.toString().split("typed_keys=true")[1].getBytes());
//    } catch (IOException e) {
//      throw new RuntimeException(e);
//    }
//    SearchResponse<News> search;
//
//    try {
//      search = elasticsearchClient.search(searchRequest, News.class);
//    } catch (IOException e) {
//      log.error(e.toString());
//      return Message.unSuccess("查询出错请重试！");
//    }


    JSONObject link = new JSONObject();
    // 完成simNews部分
    JSONObject simLink = new JSONObject();
    // 完成axis部分
    JSONObject axisLink = new JSONObject();

    try {
      getAxis(baseParam, axisLink, simLink);
    } catch (IOException e) {
      log.error("error: {}", e.getMessage(), e);
      return Message.unSuccess(e.getMessage());
    }
    // 完成data部分
    link.put("axis", axisLink);
    link.put("simNews", simLink);

    return Message.builder().code(200).message("成功").data(link).build();
  }

  private Map<String, HotChartValue> wrapCountHotMap(List<String> dateList, Object initialValue) {
    Map<String, HotChartValue> map = new LinkedHashMap<>();
    for (String date: dateList) {
      map.put(date, new HotChartValue(date, initialValue, null));
    }
    return map;
  }

  private Map<String, Map<String, Double>> wrapWebSiteInfo(LinkedHashSet<String> baseType, List<String> dateList) {
    Map<String, Map<String, Double>> map = new LinkedHashMap<>();
    for (String type: baseType) {
      map.put(type, new LinkedHashMap<>());
      for (String date: dateList) {
        map.get(type).put(date, 0.0);
      }
    }
    return map;
  }

  private Map<String, Integer> wrapAllDayTotalMap(QueryParam queryParam, List<String> lastYearDay) {
    Map<String, Integer> dayTotalMap = this.countService.getDayCountMap(
        queryParam.getStartDate(), queryParam.getEndDate());
    Map<String, Integer> ret = new LinkedHashMap<>();
    for (String day: lastYearDay) {
      ret.put(day, dayTotalMap.getOrDefault(day, 0));
    }
    return ret;
  }

  /**
   * 返回请求聚合类型，分为年维度，月维度和日维度
   * @param queryParam, 请求对象，
   * @return year, month, day
   */
  private String getTimeType(QueryParam queryParam) {
    String startDate = queryParam.getStartDate();
    String endDate = queryParam.getEndDate();
    List<String> distanceDate = RenderDateUtil.getDistanceDate(startDate, endDate);
    List<String> distanceMonth = RenderDateUtil.getDistanceMonth(distanceDate);
    if (distanceDate.size() > 365 * 3) return "year";
    if (distanceMonth.size() > 2) return "month";
    return "day";
  }

  /**
   * 处理并返回axis数据
   * @param baseParam, 即DetailSimParam
   * @param axisLink, 需要返回的link
   * @throws IOException
   */
  private void getAxis(BaseParam baseParam, JSONObject axisLink, JSONObject simLink) throws IOException {


    QueryParam queryParam = wrapQueryParam(baseParam, detailPageSize);
    List<String> calDay = RenderDateUtil.getDistanceDate(queryParam.getStartDate(),
        queryParam.getEndDate());

    List<DateHistogramBucket> dailyStatsArray = new ArrayList<>();
    List<DateHistogramBucket> monthStatsArray = new ArrayList<>();
    List<DateHistogramBucket> yearStatsArray = new ArrayList<>();
    String timeType = getTimeType(queryParam);

    getResponse(buildAxisRequest(queryParam, timeType), dailyStatsArray, monthStatsArray,
        yearStatsArray, timeType, simLink, queryParam.getCurrentPage(), queryParam.isZh());


    String[] array = queryParam.getWebSiteTypeArray().stream().map(FieldValue::_toJsonString).toArray(String[]::new);
    LinkedHashSet<String> webSiteTypeSet = new LinkedHashSet<>(Arrays.asList(array));

    Map<String, Map<String, Double>> webSiteTypeMap = wrapWebSiteInfo(webSiteTypeSet, calDay);
    List<Long> countDayList = new ArrayList<Long>(){{for (String ignored : calDay) add(0L);}};
    Map<String, HotChartValue> countLinkedHashMap = wrapCountHotMap(calDay, 0L);
    Map<String, HotChartValue> hotLinkedHashMap = wrapCountHotMap(calDay, 0.0);
    Map<String, Integer> dayTotalMap = wrapAllDayTotalMap(queryParam, calDay);
    getDailyAxis(dailyStatsArray, countDayList, countLinkedHashMap, hotLinkedHashMap,
        webSiteTypeSet, webSiteTypeMap, dayTotalMap);

    List<String> distanceMonth = null;
    LinkedHashMap<String, List<String>> distanceMonthMap = null;
    Map<String, Map<String, Double>> webSiteTypeMonthMap = null;
    Map<String, HotChartValue> countMonthMap = null;
    List<Long> countMonthList = null;
    Map<String, HotChartValue> hotMonthMap = null;
    List<String> distanceYear = null;
    LinkedHashMap<String, List<String>> distanceYearMap = null;
    Map<String, Map<String, Double>> webSiteTypeYearMap = null;
    List<Long> countYearList = null;
    Map<String, HotChartValue> countYearMap = null;
    Map<String, HotChartValue> hotYearMap = null;
    // 计算月部分
    if (timeType.equals("year") || timeType.equals("month")) {
      distanceMonth = RenderDateUtil.getDistanceMonth(calDay);
      distanceMonthMap = RenderDateUtil.getDistanceMonthMap(calDay);
      webSiteTypeMonthMap = wrapWebSiteInfo(webSiteTypeSet, distanceMonth);
      List<String> finalDistanceMonth = distanceMonth;
      countMonthList = new ArrayList<Long>(){{for (String ignored : finalDistanceMonth) add(0L);}};
      countMonthMap = wrapCountHotMap(distanceMonth, 0L);
      hotMonthMap = wrapCountHotMap(distanceMonth, 0.0);
      getMonthYearAxis(monthStatsArray, countMonthList, countMonthMap, hotMonthMap, hotLinkedHashMap,
          webSiteTypeSet, webSiteTypeMonthMap, webSiteTypeMap, distanceMonthMap);
      if (timeType.equals("year")) {
        // 计算年部分
        distanceYear = RenderDateUtil.getDistanceYear(calDay);
        distanceYearMap = RenderDateUtil.getDistanceYearMap(distanceMonth);
        webSiteTypeYearMap = wrapWebSiteInfo(webSiteTypeSet, distanceYear);
        List<String> finalDistanceYear = distanceYear;
        countYearList = new ArrayList<Long>(){{for (String ignored : finalDistanceYear) add(0L);}};
        countYearMap = wrapCountHotMap(distanceYear, 0L);
        hotYearMap = wrapCountHotMap(distanceYear, 0.0);
        getMonthYearAxis(yearStatsArray, countYearList, countYearMap, hotYearMap, hotMonthMap,
            webSiteTypeSet, webSiteTypeYearMap, webSiteTypeMonthMap, distanceYearMap);
      }
    }

    // 完成颜色包装和计算预警值
    List<Double> countAlert = new ArrayList<>();
    List<Double> hotAlert = new ArrayList<>();
    DetailSimParam detailSimParam = (DetailSimParam) baseParam;
    double alert = detailSimParam.getAlert();
    Pair<Double, Double> dayAlert = wrapColor(countLinkedHashMap, hotLinkedHashMap, countDayList);
    addCountHotAlert(dayAlert, countAlert, hotAlert, alert);
    if (timeType.equals("year") || timeType.equals("month")) {
      Pair<Double, Double> monthAlert = wrapColor(countMonthMap, hotMonthMap, countMonthList);
      addCountHotAlert(monthAlert, countAlert, hotAlert, alert);
      if (timeType.equals("year")) {
        Pair<Double, Double> yearAlert = wrapColor(countYearMap, hotYearMap, countYearList);
        addCountHotAlert(yearAlert, countAlert, hotAlert, alert);
      }
    }

    List<Double> webSiteTypeAlert = calWebSiteTypeAlert(webSiteTypeMap, webSiteTypeMonthMap, webSiteTypeYearMap, timeType);

    axisLink.put("typeStatInfo",
        wrapWebSiteType2Axis(webSiteTypeMap, webSiteTypeMonthMap, webSiteTypeYearMap, webSiteTypeAlert, timeType));
    axisLink.put("countStatInfo",
        wrapCountHot2Axis(countLinkedHashMap, countMonthMap, countYearMap, countAlert, timeType));
    axisLink.put("hotStatInfo",
        wrapCountHot2Axis(hotLinkedHashMap, hotMonthMap, hotYearMap, hotAlert, timeType));

  }

  private void addCountHotAlert(Pair<Double, Double> alert, List<Double> countAlert, List<Double> hotAlert, double alertParam) {
    countAlert.add(alert.getKey() * alertParam);
    hotAlert.add(alert.getValue() * alertParam);
  }

  private void getMonthYearAxis(List<DateHistogramBucket> dateArray,
                                List<Long> countList,
                                Map<String, HotChartValue> countBigDateMap,
                                Map<String, HotChartValue> hotBigDateMap,
                                Map<String, HotChartValue> hotSmallDateMap,
                                LinkedHashSet<String> webSiteTypeSet,
                                Map<String, Map<String, Double>> webSiteTypeBigDateMap,
                                Map<String, Map<String, Double>> webSiteTypeSmallDateMap,
                                LinkedHashMap<String, List<String>> distanceBigDateMap) {
    int i = 0;
    for (DateHistogramBucket d: dateArray) {
      String date = d.keyAsString();
      long dayTotal = d.docCount();
      countList.set(i++, dayTotal);
      HotChartValue countDay = new HotChartValue(date, dayTotal, null);
      countBigDateMap.put(date, countDay);
    }
    for (String bigDate: distanceBigDateMap.keySet()) {
      List<String> smallDates = distanceBigDateMap.get(bigDate);
      // 处理 hot
      double sumHot = 0.0;
      for (String smallDate: smallDates) {
        sumHot += (Double) hotSmallDateMap.get(smallDate).getValue();
      }
      hotBigDateMap.put(bigDate, new HotChartValue(bigDate, sumHot, null));
      // 处理webSiteType
      for (String type: webSiteTypeSet) {
        double sumType = 0.0;
        for (String smallDate: smallDates) {
          sumType += webSiteTypeSmallDateMap.get(type).get(smallDate);
        }
        webSiteTypeBigDateMap.get(type).put(bigDate, sumType);
      }
    }
  }

  private void getDailyAxis(List<DateHistogramBucket> dateArray,
                                 List<Long> countList,
                                 Map<String, HotChartValue> countMap,
                                 Map<String, HotChartValue> hotMap,
                                 LinkedHashSet<String> webSiteTypeSet,
                                 Map<String, Map<String, Double>> webSiteTypeMap,
                                 Map<String, Integer> dateTotalMap) {
    int i = 0;
    for (DateHistogramBucket d: dateArray) {
      String date = d.keyAsString();
      long dayTotal = d.docCount();
      countList.set(i++, dayTotal);
      HotChartValue countDay = new HotChartValue(date, dayTotal, null);
      countMap.put(date, countDay);

      hotMap.put(date,
          new HotChartValue(date, !dateTotalMap.containsKey(date) || dateTotalMap.get(date) == 0 ? 0: dayTotal * 1.0 / dateTotalMap.get(date) * 100 ,null));
      // 处理websiteTypes
      Aggregate aggregate = d.aggregations().get("type_counts");
      List<StringTermsBucket> websiteTypes = aggregate.sterms().buckets().array();
      for (StringTermsBucket stringTermsBucket: websiteTypes) {
        String type = (String) stringTermsBucket.key()._get();
        if (webSiteTypeSet.contains(type)) {
          webSiteTypeMap.get(type).put(date, !dateTotalMap.containsKey(date) || dateTotalMap.get(date) == 0 ? 0.0: stringTermsBucket.docCount() * 1.0 / dateTotalMap.get(date) * 100);
        }
      }
    }
  }



  private List<Double> calWebSiteTypeAlert(Map<String, Map<String, Double>> webSiteTypeDayMap,
                                           Map<String, Map<String, Double>> webSiteTypeMonthMap,
                                           Map<String, Map<String, Double>> webSiteTypeYearMap,
                                           String timeType) {
    double alertDay = 0;
    double alertMonth = 0;
    double alertYear = 0;
    int days = 0;
    int months = 0;
    int years = 0;
    List<Double> ret = new ArrayList<>();
    for (String type: webSiteTypeDayMap.keySet()) {
      days = webSiteTypeDayMap.get(type).size();
      alertDay += webSiteTypeDayMap.get(type).values().stream().reduce(0.0, Double::sum);
    }
    alertDay = days == 0 ? 0: alertDay / days;
    ret.add(alertDay);
    if (timeType.equals("year") || timeType.equals("month")) {
      for (String type: webSiteTypeMonthMap.keySet()) {
        months = webSiteTypeMonthMap.get(type).size();
        alertMonth += webSiteTypeMonthMap.get(type).values().stream().reduce(0.0, Double::sum);
      }
      alertMonth = months == 0 ? 0: alertMonth / months;
      ret.add(alertMonth);
      if (timeType.equals("year")) {
        for (String type: webSiteTypeYearMap.keySet()) {
          years = webSiteTypeYearMap.get(type).size();
          alertYear += webSiteTypeYearMap.get(type).values().stream().reduce(0.0, Double::sum);
        }
        alertYear = years == 0 ? 0: alertYear / years;
        ret.add(alertYear);
      }
    }
    return ret;
  }

  private JSONObject wrapWebSiteType2Axis(Map<String, Map<String, Double>> webSiteTypeDayMap,
                                          Map<String, Map<String, Double>> webSiteTypeMonthMap,
                                          Map<String, Map<String, Double>> webSiteTypeYearMap,
                                          List<Double> alert,
                                          String timeType
                                          ) {
    JSONObject statInfoLink = new JSONObject();
    statInfoLink.put("alerts", alert);
    ArrayList<JSONObject> series = new ArrayList<>();
    series.add(wrapWebSiteType2AxisItem(webSiteTypeDayMap));
    if (timeType.equals("year") || timeType.equals("month")) {
      series.add(wrapWebSiteType2AxisItem(webSiteTypeMonthMap));
      if (timeType.equals("year")) {
        series.add(wrapWebSiteType2AxisItem(webSiteTypeYearMap));
      }
    }
    statInfoLink.put("series", series);
    return statInfoLink;
  }

  private JSONObject wrapWebSiteType2AxisItem(Map<String, Map<String, Double>> map) {
    JSONObject dateLink = new JSONObject();
    dateLink.put("legend",
        map.keySet().stream().map(x->config.getWebSiteNameMap(x)).toArray(String[]::new));
    ArrayList<JSONObject> seriesArray = new ArrayList<>();
    for (String type: map.keySet()) {
      JSONObject seriesItem = new JSONObject();
      seriesItem.put("data", map.get(type).values());
      seriesItem.put("news_website_type", type);
      seriesItem.put("name", config.getWebSiteNameMap(type));
      seriesArray.add(seriesItem);
    }
    dateLink.put("series", seriesArray);
    Set<String> xDates = null;
    for (String s: map.keySet()) {
      xDates = map.get(s).keySet();
      break;
    }
    dateLink.put("xAxis", xDates);

    return dateLink;

  }

  private JSONObject wrapCountHot2Axis(Map<String, HotChartValue> dayMap,
                                       Map<String, HotChartValue> monthMap,
                                       Map<String, HotChartValue> yearMap,
                                       List<Double> alert,
                                       String timeType
                                       ) {
    JSONObject statInfoLink = new JSONObject();
    String[] tag;

    List<List<JSONObject>> statInfoList = new ArrayList<>();
    List<JSONObject> dayStatInfoList = new ArrayList<JSONObject>(){{
      for (HotChartValue value: dayMap.values()) {
        add(value.getJsonObject());
      }
    }};
    statInfoList.add(dayStatInfoList);
    tag = new String[]{"日"};
    if (timeType.equals("year") || timeType.equals("month")) {
      tag = new String[]{"日", "月"};
      List<JSONObject> monthStatInfoList = new ArrayList<JSONObject>(){{
        for (HotChartValue value: monthMap.values()) {
          add(value.getJsonObject());
        }
      }};
      statInfoList.add(monthStatInfoList);
      if (timeType.equals("year")) {
        List<JSONObject> yearStatInfoList = new ArrayList<JSONObject>(){{
          for (HotChartValue value: yearMap.values()) {
            add(value.getJsonObject());
          }
        }};
        tag = new String[]{"日", "月", "年"};
        statInfoList.add(yearStatInfoList);
      }
    }
    statInfoLink.put("statistic", statInfoList);
    statInfoLink.put("alerts", alert);
    statInfoLink.put("tag", tag);
    return statInfoLink;
  }

  /**
   * 给相似数量和相似热度插入颜色
   * @param countLinkedHashMap, 含有相似数量数据的map
   * @param hotChartValueLinkedHashMap, 含有相似热度数据的map
   * @param countList, 相似数量数据的list
   */
  private Pair<Double, Double> wrapColor(Map<String, HotChartValue> countLinkedHashMap,
                         Map<String, HotChartValue> hotChartValueLinkedHashMap,
                         List<Long> countList) {
    List<Long> tempCountList = new ArrayList<>(countList);
    tempCountList.sort(Long::compareTo);
    Long[] array = tempCountList.toArray(new Long[0]);
    Map<Integer, Long> tag5 = get5Tag(countList);
    if (tag5 == null) {
      return new Pair<>(0.0, 0.0);
    }
    Map<Integer, String> colorMap = config.getColorMap();

    for (String date: countLinkedHashMap.keySet()) {
      Long nowValue = (Long) countLinkedHashMap.get(date).getValue();
      int colorCast = getColorCast(array, nowValue);
      countLinkedHashMap.get(date).setColor(colorMap.get(colorCast));
      hotChartValueLinkedHashMap.get(date).setColor(colorMap.get(colorCast));
    }
    // 计算count alert
    double min = tag5.get(0);
    double max = tag5.get(4);
    double countAlert = (min + max);
    // 计算hot alert
    Double[] hotArray = hotChartValueLinkedHashMap.values().stream().map(x -> (Double) x.getValue()).toArray(Double[]::new);
    Arrays.sort(hotArray);
    min = hotArray[0];
    max = hotArray[hotArray.length - 1];
    double hotAlert = (min + max);
    return new Pair<>(countAlert, hotAlert);
  }

  private int getColorCast(Long[] array, long key) {
    if (array.length == 0) {
      return 1;
    }
    long min = array[0];
    long max = array[array.length - 1];
    if (max - min == 0) {
      return 1;
    }
    int a = (int)(((double)(key - min) * 4) / (max - min) + 1);
    if (a == 5)
      a = 4;
    return a;
  }
  /**
   * 返回四分位数，但包括0号位和末位数
   * @param countList, 相似数量数据的list
   * @return 4个标记的具体值
   */
  private Map<Integer, Long> get5Tag(List<Long> countList) {
    Long[] countArray = countList.toArray(new Long[0]);
    Arrays.sort(countArray);
    int countArrayLength = countArray.length;
    if (countArrayLength == 0) {
      return null;
    }
    Long dayCount1 = countArray[(countArrayLength + 1) / 4];
    Long dayCount2 = countArray[(countArrayLength + 1) / 2 == countArrayLength ?
        countArrayLength - 1
        : (countArrayLength + 1) / 2];
    Long dayCount3 = countArray[((countArrayLength + 1) * 3) / 4 == countArrayLength ?
        countArrayLength - 1
        : ((countArrayLength + 1) * 3) / 4];
    return new HashMap<Integer, Long>(){{
      put(0, countArray[0]);
      put(1, dayCount1);
      put(2, dayCount2);
      put(3, dayCount3);
      put(4, countArray[countArrayLength - 1]);
    }};
  }


  /**
   * 返回count、websiteType数据
   * @param queryParam, 查询条件
   * @return 创建好的查询请求
   */
  private SearchRequest buildAxisRequest(QueryParam queryParam, String timeType) {
    SearchRequest.Builder builder = buildRequest.buildRequest(queryParam).sort((SortOptions) queryParam.get3Sorts().get(2));

    SearchRequest.Builder aggregations = builder.size(queryParam.getPageSize())
        .aggregations("daily_stats", x -> x.dateHistogram(
            y -> y.field("news_publicdate")
                .calendarInterval(CalendarInterval.Day).format("yyyy-MM-dd")
        ).aggregations("type_counts",
            x_ -> x_.terms(y -> y.field("news_website_type"))));
    if (timeType.equals("month") || timeType.equals("year")) {
      aggregations = aggregations.aggregations("month_stats", x -> x.dateHistogram(
          y -> y.field("news_publicdate")
              .calendarInterval(CalendarInterval.Month).format("yyyy-MM")
      ).aggregations("type_counts",
          x_ -> x_.terms(y -> y.field("news_website_type"))));
      if (timeType.equals("year")) {
        aggregations = aggregations.aggregations("year_stats", x -> x.dateHistogram(
            y -> y.field("news_publicdate")
                .calendarInterval(CalendarInterval.Year).format("yyyy")
        ).aggregations("type_counts",
            x_ -> x_.terms(y -> y.field("news_website_type"))));
      }
    }
    SearchRequest searchRequest = aggregations.build();
    String queryJsonStr = searchRequest.toString().split("typed_keys=true")[1];
    JSONObject queryJson = JSONObject.parseObject(queryJsonStr);
    log.info("Search Request Json:{}", queryJson);
//    try {
//      new FileOutputStream("temp.file").write(queryJsonStr.getBytes());
//    } catch (IOException e) {
//      throw new RuntimeException(e);
//    }

    return searchRequest;
  }

  private void getResponse(SearchRequest searchRequest,
                           List<DateHistogramBucket> daily,
                           List<DateHistogramBucket> month,
                           List<DateHistogramBucket> year,
                           String timeType,
                           JSONObject simLink,
                           int currentPage,
                           boolean zh) throws IOException {
    SearchResponse<News> search = elasticsearchClient.search(searchRequest, News.class);
    getSimNews(search, simLink, currentPage, zh);
    Map<String, Aggregate> aggregations1 = search.aggregations();
    daily.addAll(aggregations1.get("daily_stats").dateHistogram().buckets().array());
    if (timeType.equals("year") || timeType.equals("month")) {
      month.addAll(aggregations1.get("month_stats").dateHistogram().buckets().array());
      if (timeType.equals("year")) {
        year.addAll(aggregations1.get("year_stats").dateHistogram().buckets().array());
      }
    }
  }

  /**
   * 将返回的相似新闻结果包裹到link里
   * @param search, 根据相似基数（关键词、实体）查找得到的相似新闻
   * @param link, 最终返回的link
   * @param currentPage, 当前页数
   */
  private void getSimNews(SearchResponse<News> search, JSONObject link, int currentPage, boolean zh) {
    List<Hit<News>> hits = search.hits().hits();
    link.put("currentPage", currentPage);
    List<JSONObject> newsList = new ArrayList<>();

    for (Hit<News> hit: hits) {
      assert hit.source() != null;
      JSONObject newsLink = new JSONObject();

      ResponseUtil.putCommon(newsLink, hit.source());
      ResponseUtil.putTitleContent(hit.highlight(), newsLink, hit.source(), zh);
      newsLink.put("news_sourcesite", newsLink.get("news_website"));
      newsList.add(newsLink);
    }
    link.put("news", newsList);
    assert search.hits().total() != null;

    link.put("totalResults", search.hits().total().value());
  }



  /**
   * 将DetailSimParam 包装成 QueryParam
   * @param baseParam, 即原始的DetailSimParam
   * @param detailPageSize, 相似新闻展示的页数，默认是10
   * @return 包装好的QueryParam
   */
  private QueryParam wrapQueryParam(BaseParam baseParam, Integer detailPageSize) {
    DetailSimParam detailSimParam = (DetailSimParam) baseParam;
    String searchingKeywords = getSearchingKeywordsEntities(baseParam);
    QueryParam queryParam = new QueryParam();
    if (Strings.isBlank(queryParam.getWebSiteType())) {
      queryParam.setWebSiteType("GOV,HMT,WEBSITE");
    }
    QueryParamCheckUtil.checkParam(queryParam, detailPageSize);

    queryParam.setStartDate(detailSimParam.getStartDate());
    queryParam.setEndDate(detailSimParam.getEndDate());

    queryParam.setCurrentPage(detailSimParam.getCurrentPage());
    if (detailSimParam.getPageSize() == null) {
      queryParam.setPageSize(10);
    } else {
      queryParam.setPageSize(detailSimParam.getPageSize());
    }
    queryParam.setQueryStr(searchingKeywords);
    queryParam.setSortType("sim");
    queryParam.setZh(true);
    queryParam.setSearchType("false");
    queryParam.setLikeDegree((int)(detailSimParam.getDegree() * 100) + "%");
    if (Strings.isBlank(queryParam.getStartDate()) || Strings.isBlank(queryParam.getEndDate())) {
      Pair<String, String> aYearStartEnd = RenderDateUtil.getRecent1Year();
      queryParam.setStartDate(aYearStartEnd.getKey());
      queryParam.setEndDate(aYearStartEnd.getValue());
    }
    return queryParam;
  }

//  /**
//   * 将DetailSimParam 包装成 QueryParam，不需要返回页数，服务于聚合查询
//   * @param baseParam 即原始的DetailSimParam
//
//   * @return 包装好的QueryParam
//   */
//  private QueryParam wrapQueryParam(BaseParam baseParam) {
//
//    return wrapQueryParam(baseParam, 0);
//  }

  /**
   * 转换相似性指标为查询字符串
   * @param baseParam, 即原始的DetailSimParam
   * @return 转换好的字符串
   */
  private String getSearchingKeywordsEntities(BaseParam baseParam) {
    DetailSimParam detailSimParam = (DetailSimParam) baseParam;
    List<String> searchingKeywords = new ArrayList<>();

    if (Strings.isNotBlank(detailSimParam.getKeywords())) {
      searchingKeywords.addAll(Lists.newArrayList(
          detailSimParam.getKeywordsList().stream().map(FieldValue::_toJsonString).iterator()));
    } else {
      String id = ((DetailSimParam) baseParam).getId();
      DetailParam detailParam = DetailParam.builder().id(id).build();
      Message detail = detailService.exec(detailParam);
      JSONObject data = (JSONObject) detail.getData();
      if (detailSimParam.getRecommendType().equals("keywords")) {
        searchingKeywords.addAll(EsTypeTransUtil.keyword2List(data.get("keywords")));
      } else {
        searchingKeywords.addAll(EsTypeTransUtil.entity2List(data.get("news_entities")));
      }
    }
//    searchingKeywords.replaceAll(s1 -> "(\"" + s1 + "\")");
    return String.join(" ", searchingKeywords);
  }
}
